package org.smartboot.compare.comparator;

import org.smartboot.compare.ComparatorContext;
import org.smartboot.compare.Option;
import org.smartboot.compare.difference.ComplementSetDifference;
import org.smartboot.compare.difference.Difference;
import org.smartboot.compare.difference.NullOfOneObject;
import org.smartboot.compare.utils.ComparatorUtils;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * @author qinluo
 * @version 1.0.0
 * @date 2020-08-18 15:27
 */
public class TagComparator extends AbstractComparator<String> {

    private static final String VALUE_SEPARATOR = ",";

    private static final TagComparator INSTANCE = new TagComparator();

    public static TagComparator getInstance() {
        return INSTANCE;
    }

    @Override
    public Difference compare(String expect, String actual, ComparatorContext<String> context) {
        // fast compare.
        if (Objects.equals(expect, actual)) {
            return Difference.SAME;
        }

        if (ComparatorUtils.checkBlank(expect, actual) && context.hasOption(Option.LOOSE_MODE)) {
            return Difference.SAME;
        }

        if (expect == null || actual == null) {
            return new NullOfOneObject(context.getPath(), expect, actual);
        }

        boolean hasError = false;
        Set<String> expectTags = parseTags(expect);
        Set<String> compareTags = parseTags(actual);

        Set<String> complementSetTags = new HashSet<>(expectTags.size());

        for (String key : expectTags) {

            if (!compareTags.remove(key)) {
                hasError = true;
                complementSetTags.add(key);
            }
        }

        if (hasError || !compareTags.isEmpty()) {
            return new ComplementSetDifference(context.getPath(), complementSetTags, compareTags);
        }

        return Difference.SAME;
    }

    private Set<String> parseTags(String attributes) {
        String[] expectTags = attributes.split(VALUE_SEPARATOR);

        Set<String> tags = new HashSet<>(16);

        for (String expectTag : expectTags) {
            if (expectTag == null || expectTag.trim().length() == 0) {
                continue;
            }

            tags.add(expectTag.trim());
        }

        return tags;
    }
}
